💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    로딩 중이에요... 🐣

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    21 좋아요(Like) 기능 설명 및 Ajax 준비 | ✅ 편저: 코담 운영자

    21강 - 좋아요(Like) 기능 설명 및 Ajax 준비

    기능 - 기능 설명(+ Ajax), js파일 연결


    ✨ 이보는 강의 목표

    • 좋아요 기능의 전반적인 구조 및 흐름 이해

    • Django REST API + Ajax 연동 준비

    • debounce를 활용한 클릭 중복 방지 구현


    1. 기능 설계 개요

    • 로그인 사용자가 특정 Post좋아요를 누르고 있는지 여부 확인

    • 좋아요 버튼 클릭 시 Ajax를 통해 백어렛에 요청

    • 연속 클릭 방지를 위해 debounce 적용

    • Django에서는 사용자 정보 및 좋아요 여부를 함계 응답 → 프론트에서 UI 처리에 활용


    2. Django 백어렛 API 구조

    📌 (1) 좋아요 여부 포함한 Post 응답

    class PostListView(generics.ListAPIView):
        serializer_class = PostSerializer
        permission_classes = [permissions.IsAuthenticated]
    
        def get_queryset(self):
            user = get_object_or_404(user_model, pk=self.request.user.id)
            following = user.following.all()
            return Post.objects.filter(Q(author__in=following) | Q(author=user)).order_by('-created_at')
    
        def list(self, request, *args, **kwargs):
            queryset = self.get_queryset()
            serializer = self.get_serializer(queryset, many=True, context={'request': request})
            login_user_serializer = UserSerializer(request.user, context={'request': request})
            return Response({"posts": serializer.data, "loginUser": login_user_serializer.data}, status=status.HTTP_200_OK)
    

    또는 공식 함수시곱 API:

    @api_view(['GET'])
    def posts_list_view(request):
        user = get_object_or_404(user_model, pk=request.user.id)
        following = user.following.all()
        followed_posts = Post.objects.filter(Q(author__in=following) | Q(author=user)).order_by('-created_at')
        serializer = PostSerializer(followed_posts, many=True, context={'request': request})
        login_user_serializer = UserSerializer(request.user, context={'request': request})
        return JsonResponse({"posts": serializer.data,"loginUser": login_user_serializer.data},  status=200)
    

    📌 (2) PostSerializer 설정

    class PostSerializer(serializers.ModelSerializer):
        comment_post = CommentSerializer(many=True)
        author = FeedAuthorSerializer()
        csrf_token = serializers.SerializerMethodField()
    
        class Meta:
            model = Post
            fields = (
                "id", "image", "caption", "image_likes",
                "author", "comment_post", "csrf_token"
            )
    
        def get_csrf_token(self, obj):
            request = self.context.get('request')
            return get_token(request) if request else None
    

    image_likes는 좋아요를 누르는 사용자 ID 리스트

    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = user_model
            fields = ("id", "username", "email", "profile_photo", "bio")
    

    3. 프론트엔드 - 좋아요 Ajax 처리

    📌 (1) debounce 유틸 함수

    function debounce(func, delay) {
      let timer;
      return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => func.apply(this, args), delay);
      };
    }
    

    📌 (2) 좋아요 버튼 핸들러

    async function handleLikeClick(postId, csrfToken, target) {
      const iTag = target.querySelector("i");
      const likeButton = target;
    
      if (likeButton.disabled) return;
      likeButton.disabled = true;
    
      try {
        const response = await fetch(`/posts/${postId}/post_like/`, {
          method: "POST",
          headers: {
            "X-CSRFToken": csrfToken,
          },
        });
    
        const data = await response.json();
    
        if (!response.ok || !data.success) throw new Error(data.message);
    
        if (data.message === "like") {
          iTag.classList.replace("fa-heart-o", "fa-heart");
          iTag.classList.replace("text-gray-500", "text-red-500");
        } else {
          iTag.classList.replace("fa-heart", "fa-heart-o");
          iTag.classList.replace("text-red-500", "text-gray-500");
        }
    
        target.querySelector(`#like-count-${postId}`).innerText = data.like_count;
      } catch (error) {
        console.error("좋아요 처리 실패:", error);
      } finally {
        likeButton.disabled = false;
      }
    }
    
    const debouncedHandleLikeClick = debounce(handleLikeClick, 300);
    

    📌 (3) 좋아요 버튼 HTML 템플릿

    <div class="flex items-center space-x-3"
         id="like-button-{{ post.id }}"
         onclick="debouncedHandleLikeClick('{{ post.id }}', '{{ post.csrf_token }}', this)">
    
      {% if loginUser.id in post.image_likes %}
        <i class="fa fa-heart fa-2x text-red-500 cursor-pointer hover:text-red-500"></i>
      {% else %}
        <i class="fa fa-heart-o fa-2x text-gray-500 cursor-pointer hover:text-red-500"></i>
      {% endif %}
    
      (<span id="like-count-{{ post.id }}">{{ post.image_likes|length }}</span>)
    </div>
    

    ✅ 최종 정리

    • Django API는 게시글 리스트 응답에 로그인 사용자 + 좋아요 사용자 ID 포함

    • 프론트는 Ajax로 요청 후 UI 업데이트

    • debounce로 연속 클릭 방지 (300ms 지연)

    • 좋아요 상황에 따라 하트 아이콘 실시간 전환 처리


    📅 다음 강의 예고

    실제로 좋아요를 저장하거나 취소하는 Django API 구현으로 넘어갈 계획

    TOP
    preload preload